package com.dao.base;

import com.utils.JDBCUtil;
import org.junit.Test;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**
 * @Auther: ChenJinEn
 * @Date: 2020/7/28 11:59
 * @Description: //TODO
 */
public abstract class BaseDao<T>{
    //想在对象创建之前给cls赋值,那么可以将代码写在构造方法或者代码块里
    private Class<T> cls;
    //获取T的字节码对象,T是在被继承的时候被确定具体值得
    {
        Type genericSuperclass = this.getClass().getGenericSuperclass();
        ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
        Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();//返回父类泛型的参数集合
        cls = (Class<T>) actualTypeArguments[0];
    }


    //单表的通用增删改
    private static int changeTable(String sql, Object ...args) {
        Connection con = null;
        PreparedStatement pst = null;

        try {
            con = getConnection();
            pst = con.prepareStatement(sql);
            for (int i = 0; i < args.length; i++) {
                pst.setObject(i+1,args[i] );
            }
            return pst.executeUpdate();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            close(con, pst, null);
        }
        return 0;
    }
    //单表的通用增删改(有事务版本)
    private static int changeTable1(Connection con,String sql, Object ...args) {
        PreparedStatement pst = null;
        try {
            pst = con.prepareStatement(sql);
            for (int i = 0; i < args.length; i++) {
                pst.setObject(i+1,args[i] );
            }
            return pst.executeUpdate();
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            close(null, pst, null);
        }
        return 0;
    }

    //通用查询
    public List<T> find(String sql, Object... args){
        Connection con = null;
        PreparedStatement pst = null;
        ResultSet rs = null;
        ArrayList<T> list = new ArrayList<>();
        try {
            con = getConnection();
            pst = con.prepareStatement(sql);
            for (int i = 0; i < args.length; i++) {
                pst.setObject(i+1,args[i] );
            }
            rs = pst.executeQuery();
            ResultSetMetaData metaData = rs.getMetaData();
            int columnCount = metaData.getColumnCount();//获取结果集中查出的对象列数
            while (rs.next()) {
                T t = cls.newInstance();
                for (int i = 0; i < columnCount; i++) {
                    Object columnValue = rs.getObject(i + 1);
                    //String columnName = metaData.getColumnName(i + 1);//获取表的列的列名
                    String columnName = metaData.getColumnLabel(i + 1);//获取表的列的别名,针对于表名与实体类属性名不一致,在sql中取别名
                    Field field = cls.getDeclaredField(columnName);
                    field.setAccessible(true);
                    field.set(t,columnValue);
                }
                list.add(t);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(con, pst, rs);
        }
        return list;
    }

    //通用查询(有事务版)
    public List<T> find1(Connection con,String sql, Object ...args){
        PreparedStatement pst = null;
        ResultSet rs = null;
        ArrayList<T> list = new ArrayList<>();
        try {
            pst = con.prepareStatement(sql);
            for (int i = 0; i < args.length; i++) {
                pst.setObject(i+1,args[i] );
            }
            rs = pst.executeQuery();
            ResultSetMetaData metaData = rs.getMetaData();
            int columnCount = metaData.getColumnCount();//获取结果集中查出的对象列数
            while (rs.next()) {
                T t = cls.newInstance();
                for (int i = 0; i < columnCount; i++) {
                    String columnName1 = metaData.getColumnName(i + 1);//获取表的列的列名
                    String columnName = metaData.getColumnLabel(i + 1);//获取表的列的别名,针对于表名与实体类属性名不一致,在sql中取别名
                    Object columnValue = rs.getObject(columnName1);//获取列属性对于的数据库表中的值
                    Field field = cls.getDeclaredField(columnName);
                    field.setAccessible(true);
                    field.set(t,columnValue);
                }
                list.add(t);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(null, pst, rs);
        }
        return list;
    }

    //通用查询特殊值得方法(比如统计,求和,求平均值等操作sql)
    public static <E> E getValue(String sql, Object ...args) throws Exception {
        Connection con = null;
        PreparedStatement pst = null;
        try {
            con = JDBCUtil.getConnection();
            pst = con.prepareStatement(sql);
            for (int i = 0; i < args.length; i++) {
                pst.setObject(i+1, args[i]);
            }
            ResultSet rs = pst.executeQuery();
            if (rs.next()) {
                return (E) rs.getObject(1);
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JDBCUtil.close(con, pst, null);
        }
        return null;
    }

    //通用查询特殊值得方法(比如统计,求和,求平均值等操作sql)考虑事务版本
    public static <E> E getValue1(Connection con,String sql, Object ...args){
        PreparedStatement pst = null;
        try {
            pst = con.prepareStatement(sql);
            for (int i = 0; i < args.length; i++) {
                pst.setObject(i+1, args[i]);
            }
            ResultSet rs = pst.executeQuery();
            if (rs.next()) {
                return (E) rs.getObject(1);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(null, pst, null);
        }
        return null;
    }

    //获取连接
    @Test
    public static Connection getConnection() throws ClassNotFoundException, SQLException {
        Class.forName("com.mysql.jdbc.Driver");
        return DriverManager.getConnection("jdbc:mysql://localhost:3306/db_cdm0menjin", "root", "root");
    }

    //释放资源
    public static void close(Connection con, PreparedStatement pst, ResultSet rs){
        if (con != null) {
            try {
                con.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (pst != null) {
            try {
                pst.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

}
